package com.siteseat.crudeq.broker.v1.request;

import java.util.HashSet;
import java.util.Set;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;

import com.siteseat.common.security.Permission;
import com.siteseat.common.security.SecurityException;
import com.siteseat.crudeq.broker.netty.CodecHelper;
import com.siteseat.crudeq.broker.transport.BrokerSession;
import com.siteseat.crudeq.common.raw.protocol.v1.ErrorCode;
import com.siteseat.crudeq.common.raw.protocol.v1.V1ResponseId;

/**
 *
 */
public abstract class V1AbstractRequestHandler extends AbstractRequestHandler {

  private boolean enabled;
  
  /**
   * {@inheritDoc}
   */
  @Override
  public short getVersion() {
    return 1;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isEnabled() {
    return this.enabled;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setEnabled( boolean b ) {
    this.enabled = b;
  }

  /**
   * @param session
   * @param input
   * @return
   * @throws SecurityException
   */
  protected Set<Integer> readIntegerSet( BrokerSession session, Channel ch, ChannelBuffer input ) {
    int count = input.readInt();
    if( count <= 0 ) {
      writeAndLogInvalidRequestError( ch, session, "Message ID count must be > 0" );
      return null;
    }

    Set<Integer> mids = new HashSet<Integer>( count );

    for( int i = 0; i < count; i++ ) {
      Integer n = Integer.valueOf( input.readInt() );
      mids.add( n );
    }

    return mids;
  }


  /**
   * @param session
   * @param input
   * @return
   * @throws SecurityException
   */
  protected Set<Integer> readQueueIdSet( BrokerSession session, Channel ch, ChannelBuffer input, Permission permission )
          throws SecurityException {
    Set<Integer> r = readIntegerSet( session, ch, input );
    if( r == null ) {
      return null;
    }

    for( Integer queueId: r ) {
      session.ensureGranted( queueId.toString(), permission );
    }

    return r;
  }
  
  /**
   * 
   *
   * @param ch
   */
  protected void responseOK( Channel ch ) {
    responseOK( ch, V1ResponseId.OK );
  }
  

  /**
   * 
   *
   * @param ch
   */
  protected void responseOK( Channel ch, byte responseId ) {
    ChannelBuffer output = ChannelBuffers.dynamicBuffer();

    output.writeByte( responseId);
    output.writeInt( 0 );
    ch.write( output );
  }
  

  /**
   * @param output
   * @param sess
   * @param detail
   */
  protected void writeAndLogInvalidRequestError( Channel ch, BrokerSession sess, String detail ) {
    writeAndLogError( ch, sess, ErrorCode.INVALID_REQUEST, detail );
  }

  /**
   * @param buf
   * @param sess
   * @param detail
   */
  protected void writeAndLogInvalidRequestError( Channel ch, BrokerSession sess, String detail, Exception cause ) {
    writeAndLogError( ch, sess, ErrorCode.INVALID_REQUEST, detail, cause );
  }

  /**
   * @param buf
   * @param sess
   * @param detail
   */
  protected void writeAndLogInvalidRequestError( Channel ch, BrokerSession sess ) {
    writeAndLogInvalidRequestError( ch, sess, null, null );
  }

  /**
   * @param buf
   * @param sess
   * @param detail
   */
  protected void writeAndLogInvalidRequestError( Channel ch, BrokerSession sess, Exception cause ) {
    writeAndLogInvalidRequestError( ch, sess, null, cause );
  }

  /**
   * @param buf
   * @param sess
   * @param errorCode
   * @param detail
   */
  protected void writeAndLogError( Channel ch, BrokerSession sess, ErrorCode errorCode, String detail ) {
    logError( sess, errorCode, detail );
    CodecHelper.writeError( ch, errorCode, detail );
  }

  /**
   * @param buf
   * @param sess
   * @param errorCode
   * @param detail
   */
  protected void writeAndLogError( Channel ch, BrokerSession sess, ErrorCode errorCode, String detail, Exception cause ) {
    logError( sess, errorCode, detail, cause );
    CodecHelper.writeError( ch, errorCode );
  }


}
